import requests
import time
import hmac
import hashlib
import base64
from django.conf import settings


class DingTalkSNSClient:
    """钉钉SNS客户端，用于生成签名和获取用户信息"""
    
    def __init__(self):
        self.app_key = settings.DINGTALK.get("APP_KEY")
        self.app_secret = settings.DINGTALK.get("APP_SECRET")
        self.get_user_info_url = "https://oapi.dingtalk.com/sns/getuserinfo_bycode"

    def _generate_signature(self, timestamp):
        """严格按照钉钉规范生成签名"""
        # 1. 确保 app_secret 和 timestamp 是字符串
        app_secret_str = str(self.app_secret).strip()
        timestamp_str = str(timestamp).strip()
        # 2. HMAC-SHA256 加密
        hmac_obj = hmac.new(
            app_secret_str.encode("utf-8"),
            timestamp_str.encode("utf-8"),
            digestmod=hashlib.sha256
        )
        # 3. Base64 编码（直接返回字符串，无二次编码）
        signature = base64.b64encode(hmac_obj.digest()).decode("utf-8")
        return signature

    def get_user_info_by_code(self, tmp_auth_code):
        """
        通过临时授权码获取用户信息（使用签名方式）
        
        Args:
            tmp_auth_code: 临时授权码（从回调中获取的code）
            
        Returns:
            dict: 包含unionid等用户信息的字典
            
        Raises:
            Exception: 当获取用户信息失败时抛出异常
        """
        try:
            timestamp = str(int(time.time() * 1000))  # 13位毫秒级时间戳（字符串）
            print(f"[钉钉工具类] timestamp: {timestamp}")

            signature = self._generate_signature(timestamp)
            
            # 调用钉钉接口前打印参数（便于调试）
            print(f"[钉钉工具类] 调试参数：")
            print(f"  APP_KEY: {self.app_key}")
            print(f"  APP_SECRET: {self.app_secret[:10] if self.app_secret else 'None'}...（隐藏部分内容）")
            print(f"  timestamp: {timestamp}（类型：{type(timestamp)}）")
            print(f"  signature: {signature}")

            # 构造参数（requests会自动对signature进行URL编码）
            params = {
                "accessKey": self.app_key,
                "timestamp": timestamp,
                "signature": signature  # 直接传递Base64签名，requests会自动URL编码
            }
            json_data = {"tmp_auth_code": tmp_auth_code}

            # 延长超时时间到30秒，确保有足够时间处理（授权码有效期约5分钟，目标在10分钟内完成）
            response = requests.post(
                url=self.get_user_info_url,
                params=params,  # requests会自动对signature进行URL编码
                json=json_data,
                timeout=30
            )
            print(f"[钉钉工具类] 实际请求URL: {response.url}")  # 确认签名仅被编码一次

            response_data = response.json()
            print(f"[钉钉工具类] 钉钉接口返回: {response_data}")

            if response_data.get("errcode") != 0:
                err_code = response_data.get("errcode")
                err_msg = response_data.get("errmsg", "未知错误")
                # 针对 853004 签名验证失败错误
                if err_code == 853004:
                    raise Exception(
                        f"签名验证失败（853004），请检查服务器时间和钉钉配置（APP_KEY/APP_SECRET）。错误信息：{err_msg}"
                    )
                raise Exception(
                    f"钉钉接口错误: {err_msg}（错误码：{err_code}）"
                )
            return response_data["user_info"]

        except Exception as e:
            raise Exception(f"获取钉钉用户信息失败: {str(e)}")

